package baiqitun.stupro.security.service.impl;

import baiqitun.stupro.common.constant.SysConstant;
import baiqitun.stupro.common.enums.BooleanEnum;
import baiqitun.stupro.common.exception.StuproException;
import baiqitun.stupro.common.exception.enums.support.DisabledExceptionEnum;
import baiqitun.stupro.common.exception.enums.support.ExistedExceptionEnum;
import baiqitun.stupro.common.exception.enums.support.NotFoundExceptionEnum;
import baiqitun.stupro.common.exception.enums.support.StuproExceptionEnum;
import baiqitun.stupro.common.exception.support.DisabledException;
import baiqitun.stupro.common.exception.support.ExistedException;
import baiqitun.stupro.common.exception.support.NotFoundException;
import baiqitun.stupro.common.service.EntityEnabledChecker;
import baiqitun.stupro.common.service.support.MyServiceImpl;
import baiqitun.stupro.security.entity.SysUser;
import baiqitun.stupro.security.mapper.SysUserMapper;
import baiqitun.stupro.security.service.SysUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.validation.constraints.NotBlank;

/**
 * <p>
 * 用户表 服务实现类
 * </p>
 *
 * @author kedaji
 * @since 2020-03-25
 */
@Service
public class SysUserServiceImpl extends MyServiceImpl<SysUserMapper, SysUser> implements SysUserService, EntityEnabledChecker<SysUser> {
    @Autowired
    PasswordEncoder passwordEncoder;

    /**
     * 保存用户
     * @param user 用户信息
     * @return 操作是否成功
     */
    @CachePut("user")
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean save(@Validated() SysUser user){
        try {
            String password = user.getPassword();
            user.setPassword(passwordEncoder.encode(password));
            return super.save(user);
        } catch (DuplicateKeyException e){
            throw new ExistedException(ExistedExceptionEnum.USER_EXISTED).put(SysUser.class, "username",user.getUsername());
        }
    }

    @Cacheable("user")
    @Transactional(rollbackFor = Exception.class)
    @Override
    public SysUser getUserByUsername(String username) {
        return baseMapper.selectOneByUsername(username);
    }

    @Caching(evict = @CacheEvict("user"), put = @CachePut("user"))
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updatePassword(String id, String newPassword, @NotBlank String updateBy) {
        checkEnabled(id);
        SysUser user = new SysUser();
        user.setPassword(passwordEncoder.encode(newPassword)).setId(id).setUpdateBy(updateBy);
        updateById(user);
    }

    @CacheEvict("user")
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void makeUserDisable(String id, String updateBy) {
        checkEnabled(id);
        SysUser u = new SysUser();
        u.setEnabled(BooleanEnum.FALSE.getValue()).setId(id).setUpdateBy(updateBy);
        updateById(u);
    }

    @Cacheable("user")
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void checkEnabled(String id){
        getEnabledUser(id);
    }

    @Transactional(readOnly = true, rollbackFor = Exception.class)
    @Override
    public void checkExistedByUsername(String username) {
        if (getUserByUsername(username) == null){
            throw new NotFoundException(NotFoundExceptionEnum.USER_NOT_FOUND).put(SysUser.class, "username", username);
        }
    }

    @Transactional(readOnly = true, rollbackFor = Exception.class)
    @Override
    public SysUser getEnabledUser(String id) {
        SysUser existedUser = getExistedEntity(id, new NotFoundException(NotFoundExceptionEnum.USER_NOT_FOUND));
        if (existedUser.getEnabled().equals(BooleanEnum.FALSE.getValue())){
            throw new DisabledException(DisabledExceptionEnum.USER_DISABLED).put(SysUser.class,"id", id);
        }
        return existedUser;
    }

    @Transactional(readOnly = true, rollbackFor = Exception.class)
    @Override
    public SysUser getEnabledUserByUsername(String username) {
        SysUser user = getUserByUsername(username);
        if (user.getDeleted().equals(BooleanEnum.TRUE.getValue())
                || user.getEnabled().equals(BooleanEnum.FALSE.getValue())){
            throw new DisabledException(DisabledExceptionEnum.USER_DISABLED);
        }
        return user;
    }

    @Transactional(readOnly = true, rollbackFor = Exception.class)
    @Override
    public void checkDisabled(String id, DisabledException e) {
        SysUser user = getExistedEntity(id, new NotFoundException(NotFoundExceptionEnum.USER_NOT_FOUND));
        if (BooleanEnum.FALSE.getValue().equals(user.getEnabled())){
            throw new DisabledException(DisabledExceptionEnum.USER_DISABLED);
        }
    }

    @Transactional(readOnly = true, rollbackFor = Exception.class)
    @Override
    public SysUser getEnabledEntity(String id, DisabledException e) {
        SysUser user = getExistedEntity(id, new NotFoundException(NotFoundExceptionEnum.USER_NOT_FOUND));
        if (BooleanEnum.FALSE.getValue().equals(user.getEnabled())){
            throw new DisabledException(DisabledExceptionEnum.USER_DISABLED);
        }
        return user;
    }
}
